package jdk8.lambda;

import static java.lang.System.out;
import java.util.Arrays;
import java.util.Comparator;

import org.junit.jupiter.api.Test;

import beans.Person;
import jdk8.lambda.funcionInterface.LambdaInterfaceFour;
import jdk8.lambda.funcionInterface.LambdaInterfaceOne;
import jdk8.lambda.funcionInterface.LambdaInterfaceThree;
import jdk8.lambda.funcionInterface.LambdaInterfaceTwo;

/**
 * 	静态方法引用：ClassName::methodName
 * 	实例上的实例方法引用：instanceReference::methodName
 * 	超类上的实例方法引用：super::methodName
 * 	类型上的实例方法引用：ClassName::methodName
 * 	构造方法引用：Class::new
 * 	数组构造方法引用：TypeName[]::new
 */
public class MethodReferences {
	private static Person[] ps;
	static {
		Person p1 = new Person("zhangsan", 22);
		Person p2 = new Person("lisi", 12);
		Person p3 = new Person("wangwu", 53);
		Person p4 = new Person("zhaoliu", 41);
		Person p5 = new Person("niqi", 17);
		ps = new Person[] { p1, p2, p3, p4, p5 };
	}

	@Test
	public void staticReferences() {
		/**
		静态方法引用：ClassName::methodName
		注意事项：
			被引用的方法参数列表和函数式接口中抽象方法的参数一致
			接口的抽象方法没有返回值，引用的方法可以有返回值也可以没有
			接口的抽象方法有返回值，引用的方法必须有相同类型的返回值
		*/

		out.println("++++++++++++ 静态方法引用：ClassName::methodName ++++++++++++");
		/*
		 * LambdaInterfaceOne lio = new LambdaInterfaceOne() {
		 * 
		 * @Override public void function(String s) { MethodList.staticMethod(s);
		 * 
		 * } };
		 */
		// LambdaInterfaceOne lio = x -> MethodList.staticMethod(x);
		LambdaInterfaceOne lio = MethodList::staticMethod;
		lio.function("a");
	}

	@Test
	public void instanceReference() {
		/**
		实例上的实例方法引用：instanceReference::methodName
		注意事项：
			被引用的方法参数列表和函数式接口中抽象方法的参数一致
			接口的抽象方法没有返回值，引用的方法可以有返回值也可以没有
			接口的抽象方法有返回值，引用的方法必须有相同类型的返回值
		 */
		out.println("\n\n++++++++++++ 实例上的实例方法引用：instanceReference::methodName ++++++++++++");

		/*
		 * LambdaInterfaceTwo lit = new LambdaInterfaceTwo() {
		 * 
		 * @Override public int function(String s, int i) { out.println("参数s的hashCode ："
		 * + s.hashCode()); out.println("参数i的值 ：" + i); return i * 10; } };
		 */
		/*
		 * LambdaInterfaceTwo lit = (x, y) -> { out.println("参数s的hashCode ：" +
		 * x.hashCode()); out.println("参数i的值 ：" + y); return y * 10; };
		 */
		LambdaInterfaceTwo lit = new MethodList()::instanceMethod;
		out.println(lit.function("a", 5));
	}

	@Test
	public void ThisAndSuperReference() {
		/**
		本类上的实例方法引用：this::methodName
		超类上的实例方法引用：super::methodName
		注意事项：
			被引用的方法参数列表和函数式接口中抽象方法的参数一致
			接口的抽象方法没有返回值，引用的方法可以有返回值也可以没有
			接口的抽象方法有返回值，引用的方法必须有相同类型的返回值
			
			在有继承关系的类中，若方法想调用本类或父类的成员方法
			在函数式接口抽象方法与成员方法参数列表相同，且返回值类型相同的情况下
			也可以使用this和super的方法引用来简写原本的lambda代码
		*/

		out.println("\n\n+++ 本类超类上的实例方法引用：super::methodName , this::methodName +++");

		/**
		 * 	参阅本文件最后Test Parent Child代码
		 */
		Child s = new Child();
		s.test();

	}

	@Test
	public void ClassReference() {
		/**
		类型上的实例方法引用：ClassName::methodName
			特定类型方法引用， 在Comparator函数式接口的抽象方法中传入的参数有两个，
			可是Person.sortByAge(Person p)方法参数只有一个，  第一个传入的参数
			作调用对象这就满足了特定类型的方法引用，所以可以简化成类名::非静态方法的形式
			
			与 “实例上的实例方法引用” 不同，实例方法要通过对象来调用，类型上的实例方法
			引用对应Lambda，Lambda的第一个参数会成为调用实例方法的对象。
		 */
		out.println("\n\n++++++++++++ 类型上的实例方法引用：ClassName::methodName ++++++++++++");
		/*
		 * Comparator<Person> comparator = new Comparator<Person>() {
		 * 
		 * @Override public int compare(Person p1, Person p2) { return p1.getAge() -
		 * p2.getAge(); }
		 * 
		 * };
		 */

		// Comparator<Person> comparator = (x,y) -> x.getAge() - y.getAge();
		Comparator<Person> comparator = Person::sortByAge;
		Arrays.sort(ps, comparator);
		out.println(Arrays.deepToString(ps));
	}

	@Test
	public void ConstructorReference() {
		/**
		构造方法引用：Class::new
		注意事项：
			被引用的类必须存在一个构造方法与函数式接口的抽象方法参数列表一致
		*/

		out.println("\n\n++++++++++++ 构造方法引用：Class::new ++++++++++++");

		// LambdaInterfaceThree lit = (x, y) -> out.println(x + y);
		LambdaInterfaceThree lit = Person::new;

		lit.function("a", 100);
	}

	@Test
	public void ArrayConstructorReference() {
		/**
		数组构造方法引用：TypeName[]::new
		注意事项：
			
		*/

		out.println("\n\n++++++++++++ 数组构造方法引用：TypeName[]::new ++++++++++++");

		// LambdaInterfaceFour<String> lif = (length) -> new String[length];
		LambdaInterfaceFour<String> lif = String[]::new;
		String[] arr = lif.run(5);
		System.out.println(arr.length);
	}
}

class MethodList {
	public static void staticMethod(String s) {
		out.println("参数s的hashCode ：" + s.hashCode());
	}

	public int instanceMethod(String s, int i) {
		out.println("参数s的hashCode ：" + s.hashCode());
		out.println("参数i的值 ：" + i);
		return i * 10;
	}
}





interface ITest {
	public void itMethod();
}

class Parent {
	public int buy() {
		out.println("买东西");
		return 0;
	}
}

class Child extends Parent {
	@Override
	public int buy() {
		out.println("买糖");
		return 0;
	}

	public void test() {
		// 实质代码:Test t = () -> buy();
		ITest t = this::buy;
		t.itMethod();

		// 实质代码:Test t = ()->super.buy();
		ITest t2 = super::buy;
		t2.itMethod();
	}
}
